#include "leafdatabase.h"
#include "csvparser.h"

#include <iostream>

LeafDatabase LeafDatabase::mInstance;

LeafDatabase::LeafDatabase()
{
    CSVParser::Parse("../../leafsnap-dataset/dataset/arclength_feature_multi_attempt_resize.csv",arclength_feature_csv);
    CSVParser::Parse("../../leafsnap-dataset/dataset/area_feature_multi_attempt_resize.csv",area_feature_csv);

    //assert(arclength_feature_csv.size()==area_feature_csv.size());
    features.resize(arclength_feature_csv.size());
    for(unsigned int i=0;i<arclength_feature_csv.size();i++)
    {
        //assert(arclength_feature_csv[i].size()==528);
        features[i].type=arclength_feature_csv[i][0].toStdString();
        features[i].name=arclength_feature_csv[i][1].toStdString();
        features[i].filename=arclength_feature_csv[i][2].toStdString();
        features[i].arclength_feature.resize(arclength_feature_csv[i].size()-3);
        features[i].area_feature.resize(arclength_feature_csv[i].size()-3);
        for(int j=3;j<arclength_feature_csv[i].size();j++)
        {
            features[i].arclength_feature[j-3]=arclength_feature_csv[i][j].toFloat();
            features[i].area_feature[j-3]=area_feature_csv[i][j].toFloat();
        }
        features[i].id=i;
    }
}

LeafDatabase::~LeafDatabase()
{

}

float LeafDatabase::distance(const std::vector<float>& feature1,const std::vector<float>& feature2)
{
    float distance=(float)(feature1.size()/21);
    for(unsigned int i=0;i<feature1.size();i++)
        distance-=std::min(feature1[i],feature2[i]);
    return distance;
}

bool myfunction (LeafDatabase::Entry* i, LeafDatabase::Entry* j) {
  return (i->name.compare(j->name)==0);
}

std::vector<LeafDatabase::Entry*> LeafDatabase::closestNEntries(const std::vector<float>& query_arclength_feature,const std::vector<float>& query_area_feature,int N,int ignore_id)
{
    std::vector<Entry*> entries;entries.resize(N);
    std::vector<std::pair<float,unsigned int> > distances;
    distances.resize(features.size());
    for(unsigned int i=0;i<features.size();i++)
    {
        distances[i].second=i;
        distances[i].first=distance(query_arclength_feature,features[i].arclength_feature)+distance(query_area_feature,features[i].area_feature);
    }

    std::sort(distances.begin(),distances.end());

    if(distances[0].second==ignore_id)distances.erase(distances.begin());

    int index=0;
    int search=0;
    while(index<N&&search<distances.size()){
        Entry* candidate=&features[distances[search++].second];
        bool exist=false;
        for(int i=0;i<index;i++){
            if(entries[i]->name.compare(candidate->name)==0)
            {
                exist=true;
                break;
            }
        }
        if(!exist)
            entries[index++]=candidate;
    }

    return entries;
}

std::vector<LeafDatabase::Entry*> LeafDatabase::closestNEntries(int feature_id,int N)
{
    const std::vector<float>& query_arclength_feature=features[feature_id].arclength_feature;
    const std::vector<float>& query_area_feature=features[feature_id].area_feature;

    std::vector<LeafDatabase::Entry*> entries=closestNEntries(query_arclength_feature,query_area_feature,N,feature_id);

    return entries;
}

